
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>

#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>
#include <zephyr/init.h>
#include <zephyr/irq.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/timer/nrf_grtc_timer.h>

#include <nrf.h>
#include <nrf_erratas.h>
#include <nrfx_grtc.h>
#include <nrfx_dppi.h>
#include <nrfx_ppib.h>
#include <nrfx_gpiote.h>
#include <nrfx_timer.h>

#if IS_ENABLED(CONFIG_HAS_HW_NRF_PPI)
#include <nrfx_ppi.h>
#elif IS_ENABLED(CONFIG_HAS_HW_NRF_DPPIC)
#include <nrfx_dppi.h>
#endif
#if defined(NRF54L_SERIES)
#include <nrfx_ppib.h>
#include <helpers/nrfx_gppi.h>
#endif

#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(ppi_example, LOG_LEVEL_INF);

static uint64_t g_rep_ticks;
static int g_timer_chan = -1;

K_SEM_DEFINE(g_tx_sem, 0, 1); 

static int grtc_same_domain_init(void)
{
    int err;
    // GRTC 状态指示引脚
    // GRTC->P1 (GRTC->dppic20->GPIOTE)
    // 跨域绑定流程.
    uint8_t grtc_gpio_channel;
    uint8_t dppi20_grtc_channnel;

    nrfx_dppi_t dppic20 = NRFX_DPPI_INSTANCE(20);
    const nrfx_gpiote_t grtc_gpiote = NRFX_GPIOTE_INSTANCE(NRF_DT_GPIOTE_INST(DT_NODELABEL(led3), gpios));
    uint32_t grtc_gpio_pin = NRF_DT_GPIOS_TO_PSEL(DT_NODELABEL(led3), gpios);

    // 初始化GPIOTE事件.
    err = nrfx_gpiote_channel_alloc(&grtc_gpiote, &grtc_gpio_channel);
    if (err != NRFX_SUCCESS)
    {
        return -ENODEV;
    }
    nrf_gpiote_task_configure(grtc_gpiote.p_reg, grtc_gpio_channel, grtc_gpio_pin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW);
    nrf_gpiote_task_enable(grtc_gpiote.p_reg, grtc_gpio_channel);

    // 从DPPIC20 申请一个通道.
    err = nrfx_dppi_channel_alloc(&dppic20, &dppi20_grtc_channnel);
    if (err != NRFX_SUCCESS)
    {
        return -ENODEV;
    }

    // 绑定事件通道.
    nrf_grtc_event_t grtc_event = NRF_GRTC_EVENT_COMPARE_0 + g_timer_chan * sizeof(uint32_t);
    NRF_DPPI_ENDPOINT_SETUP(
        nrf_grtc_event_address_get(NRF_GRTC, grtc_event), dppi20_grtc_channnel);
    NRF_DPPI_ENDPOINT_SETUP(
        nrf_gpiote_task_address_get(grtc_gpiote.p_reg, nrf_gpiote_out_task_get(grtc_gpio_channel)), dppi20_grtc_channnel);
    // 使能通道.
    nrfx_dppi_channel_enable(&dppic20, dppi20_grtc_channnel);

    return 0;
}


static int timer_diff_domain_init(void)
{
    int err;
    // 跨域绑定流程.
    //
    uint8_t dppi10_timer_channnel;
    uint8_t dppi20_gpiote_channnel;
    uint8_t ppib_addr_ch;
    uint8_t timer_gpio_channel;

    nrfx_dppi_t dppic10 = NRFX_DPPI_INSTANCE(10);
    nrfx_dppi_t dppic20 = NRFX_DPPI_INSTANCE(20);
    nrfx_ppib_interconnect_t ppib11_21 = NRFX_PPIB_INTERCONNECT_INSTANCE(11, 21);

    const nrfx_gpiote_t timer_gpiote = NRFX_GPIOTE_INSTANCE(NRF_DT_GPIOTE_INST(DT_NODELABEL(led1), gpios));
    uint32_t timer_gpio_pin = NRF_DT_GPIOS_TO_PSEL(DT_NODELABEL(led1), gpios);

    // 初始化GPIOTE事件.
    err = nrfx_gpiote_channel_alloc(&timer_gpiote, &timer_gpio_channel);
    if (err != NRFX_SUCCESS)
    {
        return -ENODEV;
    }
    nrf_gpiote_task_configure(timer_gpiote.p_reg, timer_gpio_channel, timer_gpio_pin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW);
    nrf_gpiote_task_enable(timer_gpiote.p_reg, timer_gpio_channel);

    // 从DPPIC10 申请通道.
    err = nrfx_dppi_channel_alloc(&dppic10, &dppi10_timer_channnel);
    if (err != NRFX_SUCCESS)
    {
        return -ENODEV;
    }

    // 申请新的PPIB通道
    err = nrfx_ppib_channel_alloc(&ppib11_21, &ppib_addr_ch);
    if (err != NRFX_SUCCESS)
    {
        return -ENODEV;
    }

    // 从DPPIC20 申请一个通道.
    err = nrfx_dppi_channel_alloc(&dppic20, &dppi20_gpiote_channnel);
    if (err != NRFX_SUCCESS)
    {
        return -ENODEV;
    }

    // 绑定事件通道.
    NRF_DPPI_ENDPOINT_SETUP(
        nrf_timer_event_address_get(NRF_TIMER10, NRF_TIMER_EVENT_COMPARE0), dppi10_timer_channnel);
    NRF_DPPI_ENDPOINT_SETUP(
        nrf_gpiote_task_address_get(timer_gpiote.p_reg, nrf_gpiote_clr_task_get(timer_gpio_channel)), dppi20_gpiote_channnel);
    NRF_DPPI_ENDPOINT_SETUP(
        nrfx_ppib_send_task_address_get(&ppib11_21.left, ppib_addr_ch), dppi10_timer_channnel);
    NRF_DPPI_ENDPOINT_SETUP(
        nrfx_ppib_receive_event_address_get(&ppib11_21.right, ppib_addr_ch), dppi20_gpiote_channnel);

    // 使能通道.
    nrfx_dppi_channel_enable(&dppic10, dppi10_timer_channnel);
    nrfx_dppi_channel_enable(&dppic20, dppi20_gpiote_channnel);

    return 0;
}

static void ppi_timer10_init(void)
{
    NRF_TIMER10->PRESCALER = 4;
    NRF_TIMER10->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
    NRF_TIMER10->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk;
    NRF_TIMER10->CC[0] = 1000;
    NRF_TIMER10->TASKS_CLEAR = 1;
    NRF_TIMER10->TASKS_START = 1;
}

/**
 * @brief 上报定时器.
 */
static void timer_compare_handler(int32_t id, uint64_t expire_time, void *user_data)
{
    nrf_grtc_sys_counter_cc_set(NRF_GRTC, g_timer_chan, g_rep_ticks);
    g_rep_ticks += 1000;
}

static void ppi_thread(void)
{
    g_timer_chan = z_nrf_grtc_timer_chan_alloc();
    z_nrf_grtc_timer_capture_prepare(g_timer_chan);

    grtc_same_domain_init();
    timer_diff_domain_init();

    ppi_timer10_init();
    
    g_rep_ticks = z_nrf_grtc_timer_read();
    g_rep_ticks += 1000;

    z_nrf_grtc_timer_set(g_timer_chan, g_rep_ticks, timer_compare_handler, NULL);
    g_rep_ticks += 1000;

    while (1)
    {
        k_sleep(K_MSEC(1000));
    }
}

K_THREAD_DEFINE(ppid_tid, 2048, ppi_thread, NULL, NULL, NULL, K_PRIO_PREEMPT(1), 0, 0);